#! /usr/bin/env python

import sys
from optparse import OptionParser
import random
import math

from common.zerror import zassert
from common.zutils import convert


class RelocationCore:
    def __init__(self, seed=0, asize='1k', physmem='16k', addresses=5, b='-1', l='-1', compute=False):
        parser = OptionParser()
        parser.add_option('-s', '--seed', default=seed, help='the random seed', action='store', type='int', dest='seed')
        parser.add_option('-a', '--asize', default=asize, help='address space size (e.g., 16, 64k, 32m, 1g)',
                          action='store',
                          type='string', dest='asize')
        parser.add_option('-p', '--physmem', default=physmem, help='physical memory size (e.g., 16, 64k, 32m, 1g)',
                          action='store', type='string', dest='psize')
        parser.add_option('-n', '--addresses', default=addresses, help='number of virtual addresses to generate',
                          action='store',
                          type='int', dest='num')
        parser.add_option('-b', '--b', default=b, help='value of base register', action='store', type='string',
                          dest='base')
        parser.add_option('-l', '--l', default=l, help='value of limit register', action='store', type='string',
                          dest='limit')
        parser.add_option('-c', '--compute', default=compute, help='compute answers for me', action='store_true',
                          dest='solve')

        (self.options, self.args) = parser.parse_args()
        self.deal_args()

    def deal_args(self):
        options = self.options

        random.seed(options.seed)
        asize = convert(options.asize)
        psize = convert(options.psize)

        if psize <= 1:
            zassert('Error: must specify a non-zero physical memory size.')

        if asize == 0:
            zassert('Error: must specify a non-zero address-space size.')

        if psize <= asize:
            zassert('Error: physical memory size must be GREATER than address space size (for this simulation)')

        #
        # need to generate base, bounds for segment registers
        #
        limit = convert(options.limit)
        base = convert(options.base)

        if limit == -1:
            limit = int(asize / 4.0 + (asize / 4.0 * random.random()))

        # now have to find room for them
        if base == -1:
            done = 0
            while done == 0:
                base = int(psize * random.random())
                if (base + limit) < psize:
                    done = 1

        print('寄存器信息:')
        print('  基地址寄存器   : 0x%08x (decimal %d)' % (base, base))
        print('  界限寄存器     : %d' % (limit))

        if base + limit > psize:
            zassert(f'Error: address space does not fit into physical memory with those base/bounds values.'
                    f'Base + Limit:{base + limit}  Psize:{psize}')

        #
        # now, need to generate virtual address trace
        #
        print('虚拟地址追踪:')
        for i in range(0, options.num):
            vaddr = int(asize * random.random())
            if not options.solve:
                print('  VA %2d: 0x%08x (十进制:%4d) --> PA or segmentation violation?' % (i, vaddr, vaddr))
            else:
                paddr = 0
                if (vaddr >= limit):
                    print('  VA %2d: 0x%08x (十进制:%4d) --> SEGMENTATION VIOLATION' % (i, vaddr, vaddr))
                else:
                    paddr = vaddr + base
                    print('  VA %2d: 0x%08x (十进制:%4d) --> VALID: 0x%08x (十进制:%4d)' % (
                    i, vaddr, vaddr, paddr, paddr))

        print('')

        if not options.solve:
            print('对每个虚拟地址，要么写下它对应的物理地址，要么指明它是否越界（段错误）。'
                  '在本模拟器中，你可以假定虚拟地址空间有着固定的大小')


def main():
    core = RelocationCore()


if __name__ == "__main__":
    main()
